bitkeeper revision 1.1159.1.556 (420951de12d7YPCDmxFldoqZYbe2cw)
authoriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Tue, 8 Feb 2005 23:57:18 +0000 (23:57 +0000)
committeriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Tue, 8 Feb 2005 23:57:18 +0000 (23:57 +0000)
Subject: [PATCH] pit-in-hv.patch

- Use ac_timer for PIT interrupt injection (more accurate time keeping)
- Accelerate some critical PIT I/O operations in the hypervisor
  (saves 15us per op). Cuts down guest timer interrupt handler execution time
  by a third.
- If the domain is scheduled out, make sure that interrupts are not lost
- Add a generic framework for device I/O interception

Signed-off-by: Edwin Zhai <edwin.zhai@intel.com>
Signed-off-by: Arun Sharma <arun.sharma@intel.com>
Signed-off-by: ian@xensource.com
15 files changed:
.rootkeys
tools/ioemu/iodev/cpu.cc
tools/ioemu/iodev/pic.cc
tools/ioemu/iodev/pic.h
tools/ioemu/iodev/pit82c54.cc
tools/ioemu/iodev/pit82c54.h
tools/ioemu/iodev/pit_wrap.cc
xen/arch/x86/domain.c
xen/arch/x86/vmx.c
xen/arch/x86/vmx_intercept.c [new file with mode: 0644]
xen/arch/x86/vmx_io.c
xen/include/asm-x86/vmx_intercept.h [new file with mode: 0644]
xen/include/asm-x86/vmx_platform.h
xen/include/asm-x86/vmx_virpit.h [new file with mode: 0644]
xen/include/public/io/ioreq.h

index 97ace4a85efee5ce8a0144e06d90c97723093bbb..bb53b189fe77949f1a685ca3cce7c76fdcfe3107 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3ddb79bccYVzXZJyVaxuv5T42Z1Fsw xen/arch/x86/trampoline.S
 3ddb79bcOftONV9h4QCxXOfiT0h91w xen/arch/x86/traps.c
 41c0c411tD3C7TpfDMiFTf7BaNd_Dg xen/arch/x86/vmx.c
+420951dcf1rSGnCH0AEYN2KjWGLG6A xen/arch/x86/vmx_intercept.c
 41c0c411ODt8uEmV-yUxpQLpqimE5Q xen/arch/x86/vmx_io.c
 41f97ef5139vN42cOYHfX_Ac8WOOjA xen/arch/x86/vmx_platform.c
 41c0c4128URE0dxcO15JME_MuKBPfg xen/arch/x86/vmx_vmcs.c
 40cf1596saFaHD5DC5zvrSn7CDCWGQ xen/include/asm-x86/uaccess.h
 41c0c412k6GHYF3cJtDdw37ee3TVaw xen/include/asm-x86/vmx.h
 41c0c412hck3QX-6_MaXaISGkngQuA xen/include/asm-x86/vmx_cpu.h
+420951dcGoqsqnmjjAtEtm6-3dM9KA xen/include/asm-x86/vmx_intercept.h
 41c0c41243jC1mcArZx_t3YkBL4lTA xen/include/asm-x86/vmx_platform.h
+420951dcqyUCe_gXA_XJPu1ix_poKg xen/include/asm-x86/vmx_virpit.h
 41c0c412lQ0NVVN9PsOSznQ-qhOiPA xen/include/asm-x86/vmx_vmcs.h
 418fbcfe_WliJPToeVM-9VStvym-hw xen/include/asm-x86/x86_32/asm_defns.h
 3ddb79c2ADvRmdexd9y3AYK9_NTx-Q xen/include/asm-x86/x86_32/current.h
index 71853afa61ebad445c74b8867847684a6c8d3382..59e4c51c0571e5759c8c1da583042bb58d8dd94d 100644 (file)
@@ -144,7 +144,11 @@ void bx_cpu_c::dispatch_ioreq(ioreq_t *req)
                        }
                }
        }
-       req->state = STATE_IORESP_READY;
+
+        /* No state change if state = STATE_IORESP_HOOK */
+        if (req->state == STATE_IOREQ_INPROCESS)
+                req->state = STATE_IORESP_READY;
+
        send_event = 1;
 }
 
index d79c37622009e1216e2d0101230ca7af96659e29..f4455508b67639b4b27d00893dc64923566d52a5 100644 (file)
@@ -855,6 +855,21 @@ bx_pic_c::IAC(void)
   BX_DBG_IAC_REPORT(vector, irq);
   return(vector);
 }
+  Bit8u
+bx_pic_c::irq_to_vec(Bit8u irq)
+{
+  Bit8u vector = 0;
+
+  if (irq >= 8 && irq <= 15)
+    vector = irq + BX_PIC_THIS s.slave_pic.interrupt_offset;
+  else if (irq != 2 && irq <= 7)
+    vector = irq + BX_PIC_THIS s.master_pic.interrupt_offset;
+  else
+    BX_ERROR(("invalid irq!\n"));
+
+  return vector;
+}
 
   void
 bx_pic_c::show_pic_state(void)
index cfdb1263ef694c9abf0afd5ee2bd2a3a5351ce84..378809d67dbc4e77a7517e20242591dcd37fd704 100644 (file)
@@ -67,7 +67,6 @@ typedef struct {
 
 
 class bx_pic_c : public bx_pic_stub_c {
-
 public:
   bx_pic_c(void);
   ~bx_pic_c(void);
@@ -77,6 +76,7 @@ public:
   virtual void   raise_irq(unsigned irq_no);
   virtual Bit8u  IAC(void);
   virtual void   show_pic_state(void);
+  Bit8u  irq_to_vec(Bit8u);
 
 private:
   struct {
index fc913b1334282f5f5a80145243f04acb8b92eefd..493faf6ee1909f68641a31c2583a59965191e489 100644 (file)
@@ -608,6 +608,37 @@ pit_82C54::clock(Bit8u cnum) {
     return 0;
   }
 
+#ifdef BX_VMX_PIT
+//extra operations when use vmx pit device model
+  void pit_82C54::write_initcount_vmx(Bit8u cnum) {
+    if(cnum>MAX_COUNTER) {
+      BX_ERROR(("Counter number incorrect\n"));
+    }
+
+    ioreq_t *req = &((vcpu_iodata_t *) shared_page)->vp_ioreq;
+    extern bx_pic_c *thePic;
+    counter_type & thisctr = counter[cnum];
+    if(req->pdata_valid) {
+      BX_ERROR(("VMX_PIT:err!pit is port io!\n"));
+    }
+
+    if (thisctr.mode == 2) {//periodic mode, need HV to help send interrupt
+      req->state = STATE_IORESP_HOOK;
+
+//      req->u.data = thisctr.inlatch * 1000 / PIT_FREQ;//init count:16 bit
+      req->u.data = thisctr.inlatch;                   //init count:16 bit
+      //get the pit irq(0)'s vector from pic DM
+      req->u.data |= ((thePic->irq_to_vec(0)) << 16 ); //timer vec:8 bit
+      req->u.data |= (cnum << 24);                     //PIT channel(0~2):2 bit
+      req->u.data |= ((thisctr.rw_mode) << 26);                //rw mode:2 bit
+
+      BX_INFO(("VMX_PIT:whole pit hook packet = 0x%llx \n", (req->u.data ) ));
+      BX_INFO(("VMX_PIT:init counter = %d ms\n", (req->u.data & 0xFFFF) ));
+    }
+
+  }
+#endif
+
   void pit_82C54::write(Bit8u address, Bit8u data) {
     if(address>MAX_ADDRESS) {
       BX_ERROR(("Counter address incorrect in data write."));
@@ -709,6 +740,9 @@ pit_82C54::clock(Bit8u cnum) {
        thisctr.inlatch=(thisctr.inlatch & (0xFF<<8)) | data;
        thisctr.null_count=1;
        thisctr.count_written=1;
+#ifdef BX_VMX_PIT
+       write_initcount_vmx(address);
+#endif
        break;
       case MSByte_multiple:
        thisctr.write_state=LSByte_multiple;
@@ -716,6 +750,9 @@ pit_82C54::clock(Bit8u cnum) {
        thisctr.inlatch=(thisctr.inlatch & 0xFF) | (data<<8);
        thisctr.null_count=1;
        thisctr.count_written=1;
+#ifdef BX_VMX_PIT
+       write_initcount_vmx(address);
+#endif
        break;
       default:
        BX_ERROR(("write counter in invalid write state."));
index bae2c2b8acfe2e68a49ae7e027cb28bcdcc49887..95d36b3973854d1431a1e14ac106c62022318180 100644 (file)
 
 #include "bochs.h"
 
+#ifdef BX_USE_VMX
+#define BX_VMX_PIT 1
+#define PIT_FREQ 1193181
+#endif
+
 
 class pit_82C54 : public logfunctions {
 
@@ -108,6 +113,10 @@ private:
 
   void print_counter(counter_type & thisctr);
 
+#ifdef BX_USE_VMX
+  void write_initcount_vmx(Bit8u cnum);
+#endif
+
 public:
   void init (void);
   void reset (unsigned type);
index ae09b3e26b59d8aee7506b9f7af8e88882cd3f0d..5fd1721073d879211087ece9639b79a4f000505c 100644 (file)
@@ -326,11 +326,13 @@ bx_pit_c::write( Bit32u   address, Bit32u   dvalue,
         (unsigned) address, (unsigned) value));
   }
 
+#ifndef BX_VMX_PIT
   if ((BX_PIT_THIS s.timer.read_OUT(0))==1) {
     DEV_pic_raise_irq(0);
   } else {
     DEV_pic_lower_irq(0);
   }
+#endif
 
   if(time_passed ||
      (BX_PIT_THIS s.last_next_event_time
@@ -419,12 +421,16 @@ bx_pit_c::periodic( Bit32u   usec_delta )
     BX_PIT_THIS s.timer.clock_all(timedelta);
     if ( (prev_timer0_out==0) ) {
       if ((BX_PIT_THIS s.timer.read_OUT(0))==1) {
+#ifndef BX_VMX_PIT
        DEV_pic_raise_irq(0);
+#endif
         prev_timer0_out=1;
       }
     } else {
       if ((BX_PIT_THIS s.timer.read_OUT(0))==0) {
+#ifndef BX_VMX_PIT
        DEV_pic_lower_irq(0);
+#endif
         prev_timer0_out=0;
       }
     }
index f544b8f29ca0283748d5cd2df1a8ef8753c6f15b..b3946df9f2c6fc3dca2abbd525ac426bd7a0c955 100644 (file)
@@ -756,6 +756,7 @@ static void relinquish_list(struct domain *d, struct list_head *list)
 #ifdef CONFIG_VMX
 static void vmx_domain_relinquish_memory(struct exec_domain *ed)
 {
+    struct vmx_virpit_t *vpit = &(ed->arch.arch_vmx.vmx_platform.vmx_pit);
     /*
      * Free VMCS
      */
@@ -764,6 +765,7 @@ static void vmx_domain_relinquish_memory(struct exec_domain *ed)
     ed->arch.arch_vmx.vmcs = 0;
     
     monitor_rm_pagetable(ed);
+    rem_ac_timer(&(vpit->pit_timer));
 }
 #endif
 
index b2dd2579693e22e6851f810abd5d3d2ec9ba2ac8..70e669183fb84e33bdb5ca5446a08a08f9ffe564 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/spinlock.h>
 #include <asm/vmx.h>
 #include <asm/vmx_vmcs.h>
+#include <asm/vmx_intercept.h>
 #include <public/io/ioreq.h>
 
 #ifdef CONFIG_VMX
@@ -359,7 +360,6 @@ static void vmx_io_instruction(struct xen_regs *regs,
     }
     p = &vio->vp_ioreq;
     p->dir = test_bit(3, &exit_qualification);  
-    set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags);
 
     p->pdata_valid = 0;
     p->count = 1;
@@ -396,6 +396,14 @@ static void vmx_io_instruction(struct xen_regs *regs,
 
     p->addr = addr;
     p->port_mm = 0;
+
+    /* Check if the packet needs to be intercepted */
+    if (vmx_io_intercept(p)) {
+       /* no blocking & no evtchn notification */
+        return;
+    } 
+
+    set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags);
     p->state = STATE_IOREQ_READY;
     evtchn_send(IOPACKET_PORT);
     do_block();
diff --git a/xen/arch/x86/vmx_intercept.c b/xen/arch/x86/vmx_intercept.c
new file mode 100644 (file)
index 0000000..54cefbe
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * vmx_intercept.c: Handle performance critical I/O packets in hypervisor space
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/types.h>
+#include <asm/vmx.h>
+#include <asm/vmx_platform.h>
+#include <asm/vmx_virpit.h>
+#include <asm/vmx_intercept.h>
+#include <public/io/ioreq.h>
+
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <asm/current.h>
+
+/* for intercepting io request after vm_exit, return value: 0--not handle; 1--handled */
+int vmx_io_intercept(ioreq_t *p)
+{
+    struct exec_domain *d = current;
+    struct vmx_handler_t *handler = &(d->arch.arch_vmx.vmx_platform.vmx_handler);
+    int i;
+    unsigned addr, offset;
+    for (i = 0; i < handler->num_slot; i++) {
+        addr   = handler->hdl_list[i].addr;
+        offset = handler->hdl_list[i].offset;
+        if (p->addr >= addr &&
+           p->addr <  addr + offset)
+           return handler->hdl_list[i].action(p);
+    }
+    return 0;
+}
+
+int register_io_handler(unsigned long addr, unsigned long offset, intercept_action_t action)
+{
+    struct exec_domain *d = current;
+    struct vmx_handler_t *handler = &(d->arch.arch_vmx.vmx_platform.vmx_handler);
+    int num = handler->num_slot;
+
+    if (num >= MAX_IO_HANDLER) {
+        printk("no extra space, register io interceptor failed!\n");
+        domain_crash();
+    }
+
+    handler->hdl_list[num].addr = addr;
+    handler->hdl_list[num].offset = offset;
+    handler->hdl_list[num].action = action;
+    handler->num_slot++;
+    return 1;
+
+}
+
+static void pit_cal_count(struct vmx_virpit_t *vpit)
+{
+    unsigned int usec_delta = (unsigned int)((NOW() - vpit->inject_point) / 1000);
+    if (usec_delta > vpit->period * 1000)
+        VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT:long time has passed from last injection!\n");
+    vpit->count = vpit->init_val - ((usec_delta * PIT_FREQ / 1000000) % vpit->init_val );
+}
+
+static void pit_latch_io(struct vmx_virpit_t *vpit)
+{
+    pit_cal_count(vpit);
+
+    switch(vpit->read_state) {
+    case MSByte:
+        vpit->count_MSB_latched=1;
+        break;
+    case LSByte:
+        vpit->count_LSB_latched=1;
+        break;
+    case LSByte_multiple:
+        vpit->count_LSB_latched=1;
+        vpit->count_MSB_latched=1;
+        break;
+    case MSByte_multiple:
+        VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT:latch PIT counter before MSB_multiple!");
+        vpit->read_state=LSByte_multiple;
+        vpit->count_LSB_latched=1;
+        vpit->count_MSB_latched=1;
+        break;
+    default:
+        BUG();
+    }
+}
+
+static int pit_read_io(struct vmx_virpit_t *vpit)
+{
+    if(vpit->count_LSB_latched) {
+        /* Read Least Significant Byte */
+        if(vpit->read_state==LSByte_multiple) {
+            vpit->read_state=MSByte_multiple;
+        }
+        vpit->count_LSB_latched=0;
+        return (vpit->count & 0xFF);
+    } else if(vpit->count_MSB_latched) {
+        /* Read Most Significant Byte */
+        if(vpit->read_state==MSByte_multiple) {
+            vpit->read_state=LSByte_multiple;
+        }
+        vpit->count_MSB_latched=0;
+        return ((vpit->count>>8) & 0xFF);
+    } else {
+        /* Unlatched Count Read */
+        VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT: unlatched read");
+        pit_cal_count(vpit);
+        if(!(vpit->read_state & 0x1)) {
+            /* Read Least Significant Byte */
+            if(vpit->read_state==LSByte_multiple) {
+                vpit->read_state=MSByte_multiple;
+            }
+            return (vpit->count & 0xFF);
+        } else {
+            /* Read Most Significant Byte */
+            if(vpit->read_state==MSByte_multiple) {
+                vpit->read_state=LSByte_multiple;
+            }
+            return ((vpit->count>>8) & 0xFF);
+        }
+    }
+}
+
+/* vmx_io_assist light-weight version, specific to PIT DM */ 
+static void resume_pit_io(ioreq_t *p)
+{
+    execution_context_t *ec = get_execution_context();
+    unsigned long old_eax = ec->eax;
+    p->state = STATE_INVALID;
+
+    switch(p->size) {
+    case 1:
+        ec->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
+        break;
+    case 2:
+        ec->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
+        break;
+    case 4:
+        ec->eax = (p->u.data & 0xffffffff);
+        break;
+    default:
+        BUG();
+    }
+}
+
+/* the intercept action for PIT DM retval:0--not handled; 1--handled */
+int intercept_pit_io(ioreq_t *p)
+{
+    struct exec_domain *d = current;
+    struct vmx_virpit_t *vpit = &(d->arch.arch_vmx.vmx_platform.vmx_pit);
+
+    if (p->size != 1 ||
+        p->pdata_valid ||
+        p->port_mm)
+        return 0;
+    
+    if (p->addr == 0x43 &&
+       p->dir == 0 &&                          /* write */
+        ((p->u.data >> 4) & 0x3) == 0 &&       /* latch command */
+        ((p->u.data >> 6) & 0x3) == (vpit->channel)) {/* right channel */
+        pit_latch_io(vpit);
+       return 1;
+    }
+
+    if (p->addr == (0x40 + vpit->channel) &&
+       p->dir == 1) {  /* read */
+        p->u.data = pit_read_io(vpit);
+        resume_pit_io(p);
+       return 1;
+    }
+
+    return 0;
+}
+
+/* hooks function for the PIT initialization response iopacket */
+static void pit_timer_fn(unsigned long data)
+{
+    struct vmx_virpit_t *vpit = (struct vmx_virpit_t*)data;
+
+    /* rearm itself */
+    vpit->pit_timer.expires = NOW() + MILLISECS(vpit->period);
+
+    /*set the pending intr bit in shared page, send evtchn notification to myself*/
+    if (test_and_set_bit(vpit->vector, vpit->intr_bitmap))
+        vpit->pending_intr_nr++; /* if originaly set, then count the pending intr */
+
+    add_ac_timer(&(vpit->pit_timer));
+}
+
+
+/* Only some PIT operations such as load init counter need a hypervisor hook.
+ * leave many other operations in user space DM
+ */
+void vmx_hooks_assist(struct exec_domain *d)
+{
+    vcpu_iodata_t *vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
+    ioreq_t *p = &vio->vp_ioreq;
+    unsigned long *intr = &(vio->vp_intr[0]);
+    struct vmx_virpit_t *vpit = &(d->arch.arch_vmx.vmx_platform.vmx_pit);
+    int rw_mode;
+
+    if (p->state == STATE_IORESP_HOOK) { /*load init count*/
+        vpit->init_val = (p->u.data & 0xFFFF) ; /* frequency(ms) of pit */
+        vpit->period = (vpit->init_val) * 1000 / PIT_FREQ; /* frequency(ms) of pit */
+        vpit->vector = ((p->u.data >> 16) & 0xFF);
+        vpit->channel = ((p->u.data >> 24) & 0x3);
+
+       vpit->count_LSB_latched = 0;
+       vpit->count_MSB_latched = 0;
+
+        rw_mode = ((p->u.data >> 26) & 0x3);
+        switch(rw_mode) {
+        case 0x1:
+            vpit->read_state=LSByte;
+            break;
+        case 0x2:
+            vpit->read_state=MSByte;
+            break;
+        case 0x3:
+            vpit->read_state=LSByte_multiple;
+            break;
+        default:
+            printk("VMX_PIT:wrong PIT rw_mode!\n");
+            break;
+        }
+
+        vpit->intr_bitmap = intr;
+
+        /* set up the actimer */
+        init_ac_timer(&(vpit->pit_timer));
+        vpit->pit_timer.cpu = 0; /*FIXME: change for SMP */
+        vpit->pit_timer.data = (unsigned long)vpit;
+        vpit->pit_timer.function = pit_timer_fn;
+        pit_timer_fn((unsigned long)vpit); /* timer seed */
+
+        /*restore the state*/
+        p->state = STATE_IORESP_READY;
+
+       /* register handler to intercept the PIT io when vm_exit */
+       register_io_handler(0x40, 4, intercept_pit_io); 
+    }
+
+}
index 440b51d5b4ad53ce262796d6edce1a206809a9c4..3241ada86508cac7a7cb5d079623c7f4f1e5a075 100644 (file)
@@ -31,6 +31,7 @@
 #include <xen/event.h>
 #include <public/io/ioreq.h>
 #include <asm/vmx_platform.h>
+#include <asm/vmx_virpit.h>
 
 #ifdef CONFIG_VMX
 
@@ -197,6 +198,11 @@ void vmx_io_assist(struct exec_domain *ed)
         domain_crash();
     }
     p = &vio->vp_ioreq;
+
+    if (p->state == STATE_IORESP_HOOK){
+        vmx_hooks_assist(ed);
+    }
+
     /* clear IO wait VMX flag */
     if (test_bit(ARCH_VMX_IO_WAIT, &ed->arch.arch_vmx.flags)) {
         if (p->state != STATE_IORESP_READY) {
@@ -337,6 +343,7 @@ void vmx_intr_assist(struct exec_domain *d)
 {
     int highest_vector = find_highest_pending_irq(d);
     unsigned long intr_fields, eflags;
+    struct vmx_virpit_t *vpit = &(d->arch.arch_vmx.vmx_platform.vmx_pit);
 
     if (highest_vector == -1)
         return;
@@ -355,12 +362,19 @@ void vmx_intr_assist(struct exec_domain *d)
         return;
     }
         
-    clear_highest_bit(d, highest_vector); 
+    if (vpit->pending_intr_nr && highest_vector == vpit->vector)
+        vpit->pending_intr_nr--;
+    else
+        clear_highest_bit(d, highest_vector); 
+
     intr_fields = (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR | highest_vector);
     __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
 
     __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
 
+    if (highest_vector == vpit->vector)
+        vpit->inject_point = NOW();
+
     return;
 }
 
diff --git a/xen/include/asm-x86/vmx_intercept.h b/xen/include/asm-x86/vmx_intercept.h
new file mode 100644 (file)
index 0000000..54f118c
--- /dev/null
@@ -0,0 +1,31 @@
+
+#ifndef _VMX_INTERCEPT_H
+#define _VMX_INTERCEPT_H
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/time.h>
+#include <xen/errno.h>
+#include <public/io/ioreq.h>
+
+
+#define MAX_IO_HANDLER 6
+
+typedef int (*intercept_action_t)(ioreq_t*);
+
+struct vmx_handler_t {
+    int num_slot;
+    struct {
+        unsigned long       addr;
+        unsigned long       offset;
+        intercept_action_t  action;
+    } hdl_list[MAX_IO_HANDLER];
+};
+
+/* global io interception point in HV */
+extern int vmx_io_intercept(ioreq_t*);
+extern int register_io_handler(unsigned long, unsigned long, intercept_action_t);
+
+
+#endif /* _VMX_INTERCEPT_H */
index 4557e5d08335fcd4691409850e66d52583a3095a..63cb74d90f341ca52ebf718838b9d2aabe2a791c 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <public/xen.h>
 #include <asm/e820.h>
+#include <asm/vmx_virpit.h>
+#include <asm/vmx_intercept.h>
 
 #define MAX_OPERAND_NUM 3
 #define I_NAME_LEN  16
@@ -79,6 +81,8 @@ struct mi_per_cpu_info
 struct virutal_platform_def {
     unsigned long          *real_mode_data; /* E820, etc. */
     unsigned long          shared_page_va;
+    struct vmx_virpit_t    vmx_pit;
+    struct vmx_handler_t   vmx_handler;
     struct mi_per_cpu_info mpci;            /* MMIO */
 };
 
diff --git a/xen/include/asm-x86/vmx_virpit.h b/xen/include/asm-x86/vmx_virpit.h
new file mode 100644 (file)
index 0000000..91a08c2
--- /dev/null
@@ -0,0 +1,81 @@
+
+#ifndef _VMX_VIRPIT_H
+#define _VMX_VIRPIT_H
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/time.h>
+#include <xen/errno.h>
+#include <xen/ac_timer.h>
+#include <asm/vmx_vmcs.h>
+
+#define PIT_FREQ 1193181
+
+#define LSByte 0
+#define MSByte 1
+#define LSByte_multiple 2
+#define MSByte_multiple 3
+
+struct vmx_virpit_t {
+    /* for simulation of counter 0 in mode 2*/
+    int vector;                                /* the pit irq vector */
+    unsigned int period;               /* the frequency. e.g. 10ms*/
+    unsigned int channel;              /* the pit channel, counter 0~2 */
+    unsigned long *intr_bitmap;
+    unsigned int pending_intr_nr;      /* the couner for pending timer interrupts */
+    unsigned long long inject_point;   /* the time inject virt intr */
+    struct ac_timer pit_timer;         /* periodic timer for mode 2*/
+
+    /* virtual PIT state for handle related I/O */
+    int read_state;
+    int count_LSB_latched;
+    int count_MSB_latched;
+
+    unsigned int count;                /* the 16 bit channel count */
+    unsigned int init_val;     /* the init value for the counter */
+
+} ;
+
+/* to hook the ioreq packet to get the PIT initializaiton info */
+extern void vmx_hooks_assist(struct exec_domain *d);
+
+#endif /* _VMX_VIRPIT_H_ */
+
+#ifndef _VMX_VIRPIT_H
+#define _VMX_VIRPIT_H
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/time.h>
+#include <xen/errno.h>
+#include <xen/ac_timer.h>
+#include <asm/vmx_vmcs.h>
+
+#define PIT_FREQ 1193181
+
+#define LSByte 0
+#define MSByte 1
+#define LSByte_multiple 2
+#define MSByte_multiple 3
+
+struct vmx_virpit_t {
+    /* for simulation of counter 0 in mode 2*/
+    int vector;                                /* the pit irq vector */
+    unsigned int period;               /* the frequency. e.g. 10ms*/
+    unsigned int channel;              /* the pit channel, counter 0~2 */
+    unsigned long *intr_bitmap;
+    unsigned int pending_intr_nr;      /* the couner for pending timer interrupts */
+    unsigned long long inject_point;   /* the time inject virt intr */
+    struct ac_timer pit_timer;         /* periodic timer for mode 2*/
+
+    /* virtual PIT state for handle related I/O */
+    int read_state;
+    int count_LSB_latched;
+    int count_MSB_latched;
+
+    unsigned int count;                /* the 16 bit channel count */
+    unsigned int init_val;     /* the init value for the counter */
+
+} ;
+
+#endif /* _VMX_VIRPIT_H_ */
index ac47cd9ec5f60d518695979111f9101b39a1175a..2f01d88385cdda21283c40c713f9fda59de65d18 100644 (file)
@@ -27,6 +27,7 @@
 #define STATE_IOREQ_READY       1
 #define STATE_IOREQ_INPROCESS   2
 #define STATE_IORESP_READY      3
+#define STATE_IORESP_HOOK       4
 
 #define IOPACKET_PORT   2